#include "vdrive.h"
#include "WProgram.h"
#include <string.h>  //try and remove this include

//#define VDRIVE_DEBUG

#define vdrive_HALF_CLOCK 5 // in microseconds; minimum is 0.08 but must be integer

vdrive::vdrive(int pinCLK, int pinCS, int pinDI, int pinDO)
: 
pinSPICLK (pinCLK),
pinSPICS (pinCS),
pinSPIDI (pinDI),
pinSPIDO (pinDO)
{
  pinMode(pinSPICLK,OUTPUT);
  digitalWrite(pinSPICLK,LOW);

  pinMode(pinSPIDI,OUTPUT);
  digitalWrite(pinSPIDI,LOW);

  pinMode(pinSPIDO,INPUT);

  pinMode(pinSPICS,OUTPUT);
  digitalWrite(pinSPICS,LOW);
}

vdrive_READ vdrive::read()
{
  struct vdrive_READ ret = {
    0,0  };
  delay(5);
  for(int i=0; i<=12; i++)
  {
    digitalWrite(pinSPICLK,LOW);
    if( i <= 2 )
    {
      digitalWrite(pinSPICS,HIGH);
      digitalWrite(pinSPIDI,(i == 0 || i == 1) ? HIGH : LOW );
    }
    if( i == 12 )
    {
      digitalWrite(pinSPICS,LOW);
    }
    delayMicroseconds(vdrive_HALF_CLOCK);
    digitalWrite(pinSPICLK,HIGH);
    delayMicroseconds(vdrive_HALF_CLOCK);
    if( i >= 3 && i <= 10 )
    {
      ret.value = (ret.value << 1) | ((digitalRead(pinSPIDO) == HIGH) ? 1 : 0);
    }
    if( i == 11 )
    {
      ret.isNew = !digitalRead(pinSPIDO);
    }
  }
  digitalWrite(pinSPICLK,LOW);
  ret.value = ret.value >> 1;
  #ifdef VDRIVE_DEBUG
  if( ret.isNew )
    SerialUSB.print(ret.value);
  #endif
  return ret;
}

unsigned char vdrive::readStatus()
{
  struct vdrive_READ ret = {
    0,0  };
  for(int i=0; i<=12; i++)
  {
    digitalWrite(pinSPICLK,LOW);
    if( i <= 2 )
    {
      digitalWrite(pinSPICS,HIGH);
      digitalWrite(pinSPIDI,(i == 0 || i == 1) ? HIGH : HIGH );
    }
    if( i == 12 )
    {
      digitalWrite(pinSPICS,LOW);
    }
    delayMicroseconds(vdrive_HALF_CLOCK);
    digitalWrite(pinSPICLK,HIGH);
    delayMicroseconds(vdrive_HALF_CLOCK);
    if( i >= 3 && i <= 10 )
    {
      ret.value = (ret.value << 1) | ((digitalRead(pinSPIDO) == HIGH) ? 1 : 0);
    }
    if( i == 11 )
    {
      ret.isNew = !digitalRead(pinSPIDO);
    }
  }
  digitalWrite(pinSPICLK,LOW);
  ret.value = ret.value >> 1;
  return ret.value;
}

unsigned char vdrive::write(unsigned char out)
{
#ifdef VDRIVE_DEBUG
  if( out == 0x0d )
    SerialUSB.println();
  else
    SerialUSB.print((char)out);
#endif
  unsigned char ret = 0;
  for(int i=0; i<=12; i++)
  {
    digitalWrite(pinSPICLK,LOW);
    if( i <= 2 )
    {
      digitalWrite(pinSPICS,HIGH);
      digitalWrite(pinSPIDI,(i == 0) ? HIGH : LOW );
    }
    if( i == 12 )
    {
      digitalWrite(pinSPICS,LOW);
    }
    if( i >= 3 && i <= 10 )
    {
      digitalWrite(pinSPIDI, (out & (1<<(8-(i-3)-1))) ? HIGH : LOW);
    }
    delayMicroseconds(vdrive_HALF_CLOCK);
    digitalWrite(pinSPICLK,HIGH);
    delayMicroseconds(vdrive_HALF_CLOCK);
    if( i == 11 )
    {
      ret = digitalRead(pinSPIDO);
    }
  }
  digitalWrite(pinSPICLK,LOW);
  delay(5);
  return ret;
}

unsigned char vdrive::writeString(char* in)
{
  unsigned char ret=0;
  int i=0;
  while( in[i] != '\0' ) 
  {
    ret |= this->write(in[i]);
    i++;
  }
  return ret;
}

int isPrompt(char* in)
{
#ifdef VDRIVE_DEBUG
  SerialUSB.print("Is this a prompt? ");
  SerialUSB.println(in);
#endif
  if( strstr(in,"D:\\>") )
    return 1;
  return 0;
}

void vdrive::clearConsole()
{
  char response[64];
  do
  {
    int i=0;
    vdrive_READ vdr = this->read();
    while( vdr.isNew ) 
    {
      response[i++] = vdr.value;
      vdr = this->read();
    }
    response[i] = 0;
  } 
  while( !isPrompt(response) );
#ifdef VDRIVE_DEBUG
  SerialUSB.print("Clear Response: ");
  SerialUSB.println(response);
#endif
}

void vdrive::init()
{
  int i=0;
  char response[32];
  int tries=0;
  vdrive_READ vdr;
  this->writeString("E");
  this->write(0x0d);
  //delay(5000);	
get_response: 
  i=0;
  vdr = this->read();
  while( vdr.isNew )
  {
    response[i++] = vdr.value;
    vdr = this->read();
  }
  response[i] = 0;
  if( i-2 >= 0 && response[i-2] == 'E' && response[i-1] == 0x0d )
  {
#ifdef VDRIVE_DEBUG
    SerialUSB.println("Sync\'ed");
#endif
  }
  else
  {
#ifdef VDRIVE_DEBUG
    SerialUSB.println("Unsync\'ed");
#endif
    //delay(1000);
    tries++;
    if( tries > 4 ) 
    {
#ifdef VDRIVE_DEBUG
      SerialUSB.println("giving up");
#endif
      goto get_response;
    }
    goto get_response;
  }
  // use ASCII representations of numbers (command IPA)
  this->writeString("IPA");
  this->write(0x0d);
  delay(500);
  i=0;
  vdr = this->read();
  while( vdr.isNew )
  {
    response[i++] = vdr.value;
    vdr = this->read();
  }
  response[i] = 0;
#ifdef VDRIVE_DEBUG
  SerialUSB.print("IPA Response: ");
  SerialUSB.println(response);
#endif
}


void vdrive::fopen(char* input)
{
  this->writeString("OPW ");
  int i=0;
  while( input[i] != 0 )
  {
    this->write(input[i++]);
  }
  this->write(0x0d);
  delay(500);
  i = 0;
  char response[32];
  vdrive_READ vdr = this->read();
  while( vdr.isNew ) 
  {
    response[i++] = vdr.value;
    vdr = this->read();
  }
  response[i] = 0;
#ifdef VDRIVE_DEBUG
  SerialUSB.print("OPW Response: ");
  SerialUSB.println(response);
#endif
}

int to_valid_digit(char ch)
{
  if(ch>='0'&&ch<='9')
    return(ch - '0');
  return(ch - 55);
}

char* vdrive::fread(char* input)
{
  int number[10],i,j,hex_num=0,dec_num=0,newtemp[10],rem,k,n;
  char temp[32];
  this->writeString("DIR ");
  
  while( input[i] != 0 ) 
  {
    this->write(input[i++]);
  }
  this->write(0x0d);
  delay(500);
  i = 0;
  char response[100];
  vdrive_READ vdr = this->read();
  while( vdr.isNew ) 
  {
    response[i++] = vdr.value;
    vdr = this->read();
  }
  response[i] = 0;
  #ifdef VDRIVE_DEBUG
    SerialUSB.print("DIR Response: ");
    SerialUSB.println(response);
  #endif
  // Calculation of the size of the file
  i=0,k=0;
  //SerialUSB.println("pre loop");
  while(response[i]!='$')
  {
    i=i+1;
    if(i==100-1)
    {
      //SerialUSB.println("error in file read DIR commandD");
      return response;
    }
  }
  //SerialUSB.println("post loop");
  i++;
  //SerialUSB.println(response[i]);
  uint32 res = to_valid_digit(response[i+12]);
  //SerialUSB.println(res);
  res = (res<<4) + to_valid_digit(response[i+13]);
  res = (res<<4) + to_valid_digit(response[i+8]);
  res = (res<<4) + to_valid_digit(response[i+9]);
  res = (res<<4) + to_valid_digit(response[i+4]);
  res = (res<<4) + to_valid_digit(response[i+5]);
  res = (res<<4) + to_valid_digit(response[i+0]);
  res = (res<<4) + to_valid_digit(response[i+1]);
  /*for(j=i+1;(response[j]!='D' && response[j+1]!=':');j++)
  {
     if(response[j]!='$' || response[j]!=' ')
       temp[k++]=response[j];
  }
  temp[k]= 0;*/
  //SerialUSB.print("Size of the file:");
  //SerialUSB.println(res);
  /*for(i=0;temp[i]!='\0';i++)
  {
    number[i]=temp[i]-48;
  }
  for(j=0;j<i;j++)
  {
    dec_num=dec_num*16+number[j];
  }*/
  //printf("\n%d",dec_num);
  dec_num = res;
  j=0;
  while(dec_num>0)
  {
    rem = dec_num%10;
    newtemp[j] = rem+48;
    dec_num = dec_num/10;
    j=j+1;
  }
  for(i=0,k=j-1;i<j;i++,k--)
  {
    temp[k]=newtemp[i];
  }
  n=j;
  //delay(2000);
  /*
  for(i=0;i<n;i++)
  {
    SerialUSB.println(newtemp[i]);
  }*/
  this->writeString("OPR ");
  i=0;
  while( input[i] != 0 ) 
  {
    this->write(input[i++]);
  }
  this->write(0x0d);
  i=0;
  char response5[1000];
  vdr = this->read();
  while( vdr.isNew ) 
  {
    response5[i++] = vdr.value;
    vdr = this->read();
  }
  response5[i] = 0;
  #ifdef VDRIVE_DEBUG
    SerialUSB.print("OPR Response: ");
    SerialUSB.println(response5);
  #endif
  this->writeString("SEK ");
  this->write(0x30);
  this->write(0x0d);
  delay(500);
  i=0;
  char response2[1000];
  vdrive_READ vdr2 = this->read();
  while( vdr2.isNew ) 
  {
    response2[i++] = vdr2.value;
    vdr2 = this->read();
  }
  response2[i] = 0;
  #ifdef VDRIVE_DEBUG
    SerialUSB.print("SEK Response: ");
    SerialUSB.println(response2); 
  #endif	
  this->writeString("RDF ");
  //SerialUSB.println("Writing the size of the file...");
  for(i=0;i<n;i++)
  {
    this->write(temp[i]);
    //SerialUSB.println(temp[i]);
  }
  this->write(0x0d);
  delay(500);
  i=0;
  char response3[codeMax];
  vdrive_READ vdr3 = this->read();
  while( vdr3.isNew ) 
  { 
    response3[i] = vdr3.value;
    if(response3[i] == 10 || response3[i]==0x00)
    {      
      response3[i+1] = 0;
      //SerialUSB.println(response3);
      reader(response3);
      i = -1;
    }
    i = i+1;  
    vdr3 = this->read();
  }

  response3[i] = 0;
  #ifdef VDRIVE_DEBUG
    SerialUSB.print("RDF Response: ");
    SerialUSB.println(response3);
  #endif
  char response4[10000];
  i=0,j=0;
  while(response3[i]!=':')
  {
    response4[i]=response3[i];
    i=i+1;
  }
  response4[i-1] = 0;
#ifdef VDRIVE_DEBUG
  SerialUSB.print("Response After Reading File: ");
  SerialUSB.println(response4);
#endif
  return response4;
}

void vdrive::fputs(char* data)
{
  int len = 0;
  while( data[len++] != 0 );
  this->writeString("WRF ");
  int i =0;
  char usezero=0;
  long temlen = len-1;
  for(int j=10000; j>=1; j/=10) 
  {
    if( temlen/j == 0 )
    {
      if( usezero )
      { 
        this->write('0'); 
      }
    }
    else
    {
      usezero = 1;
      this->write( '0' + (temlen/j) );
      temlen %= j;
    }
  }
  this->write(0x0d);
  for(i=0; i<(len-1); i++)
  { 
    this->write( data[i] ); 
  }
  delay(10);
  i=0;
  char response[32];
  vdrive_READ vdr = this->read();
  while( vdr.isNew ) 
  {
    response[i++] = vdr.value;
    vdr = this->read();
  }
  response[i] = 0;
#ifdef VDRIVE_DEBUG
  SerialUSB.print("WRF Response: ");
  SerialUSB.println(response);
#endif
}

void vdrive::fclose(char* input)
{
  this->writeString("CLF ");
  int i=0;
  while( input[i] != 0 ) {
    this->write(input[i++]);
  }
  this->write(0x0d);
  delay(500);
  i=0;
  char response[32];
  vdrive_READ vdr = this->read();
  while( vdr.isNew ) 
  {
    response[i++] = vdr.value;
    vdr = this->read();
  }
  response[i] = 0;
#ifdef VDRIVE_DEBUG
  SerialUSB.print("CLF Response: ");
  SerialUSB.println(response);
#endif
}


